﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using LCL.Reflection;
using LCL.Serialization;

namespace LCL
{
    public class ModelUtility
    {
        private static readonly Hashtable hashDict = Hashtable.Synchronized(new Hashtable(10240));
        private static DateTime defaultDate = new DateTime(1900, 1, 1);

        // Id=1 and Name like '%TClassM%' and AddDate between '2018-10-26 0:00:00' and '2018-10-27 9:52:04' 
        public static string GetQuerySQL<T>(T model, bool ignoreDefault = true)
        {
            string query = "";
            if (model != null)
            {
                PropertyInfo[] pis = Reflect<T>.GetPropertyAll();
                StringBuilder sb = new StringBuilder();
                Type tp = typeof(DateTime);
                for (int i = 0, len = pis.Length; i < len; i++)
                {
                    PropertyInfo pi = pis[i];
                    object v = pi.GetValue(model, null);
                    Type type = pi.PropertyType;
                    bool isDefault = JudgeDefault(type, v);

                    if (!isDefault || (isDefault && !ignoreDefault))
                    {
                        string prePN = Reflect<T>.GetAttributeName(pi);
                        if (type.Equals(typeof(DateTime)))
                        {
                            DateTime dt = Convert.ToDateTime(v);
                            sb.Append(string.Format("{0}{1} between '{2}'  and  '{3}' and ", prePN, pi.Name, dt.Date.ToString(), dt.AddDays(1).ToString()));
                        }
                        else if (type.IsValueType)
                        {
                            sb.Append(string.Format("{0}{1}={2} and ", prePN, pi.Name, v));
                        }
                        else
                        {
                            sb.Append(string.Format("{0}{1} like '%{2}%' and ", prePN, pi.Name, v));
                        }
                    }
                }
                string tmpQuery = sb.ToString();
                if (tmpQuery.EndsWith("and "))
                {
                    tmpQuery = tmpQuery.Remove(tmpQuery.Length - 4, 4);
                }
                query = tmpQuery;
            }
            return query;
        }
        // Id=1&Name=TClassM&AddDate=2018-10-26 10:00:31
        public static string GetQueryString<T>(T obj, bool ignoreDefault = true)
        {
            StringBuilder sb = new StringBuilder();
            if (obj != null)
            {
                PropertyInfo[] pis = Reflect<T>.GetPropertyAll();
                for (int i = 0, len = pis.Length; i < len; i++)
                {
                    PropertyInfo pi = pis[i];
                    string pn = pi.Name;
                    object v = pi.GetValue(obj, null);
                    Type type = pi.PropertyType;
                    bool isDefault = JudgeDefault(type, v);

                    if (!isDefault || (isDefault && !ignoreDefault))
                    {
                        if (v != null)
                        {
                            if (IsBaseType(type))
                            {
                                if (!string.IsNullOrEmpty(v.ToString()))
                                {
                                    sb.Append(pn + "=" + v.ToString() + "&");
                                }
                            }
                            else
                            {
                                sb.Append(pn + "=" +SerializerFactory.Factory().Serialize(v) + "&");
                            }
                        }
                    }
                }
                if (sb.Length > 1)
                {
                    sb.Remove(sb.Length - 1, 1);
                }
            }
            return sb.ToString();
        }
        //Id=1&Name=TClassM&AddDate=2018-10-26 10:02:31
        public static string GetQueryString<T>(T obj, bool ignoreNull, bool ignoreDefault = true)
        {
            StringBuilder sb = new StringBuilder();
            if (obj != null)
            {
                PropertyInfo[] pis = typeof(T).GetProperties();
                for (int i = 0, len = pis.Length; i < len; i++)
                {
                    PropertyInfo pi = pis[i];
                    Type type = pi.PropertyType;
                    string pn = pi.Name;
                    object v = pi.GetValue(obj,null);
                    bool isDefault = JudgeDefault(type, v);

                    if (!isDefault || (isDefault && !ignoreDefault))
                    {
                        if (v != null)
                        {
                            if (IsBaseType(type))
                            {
                                if (!string.IsNullOrEmpty(v.ToString()))
                                {
                                    sb.Append(pn + "=" + v.ToString() + "&");
                                }
                                else if (!ignoreNull)
                                {
                                    sb.Append(pn + "=''&");
                                }
                            }
                            else
                            {
                                sb.Append(pn + "=" + SerializerFactory.Factory().Serialize(v) + "&");
                            }
                        }
                    }
                }
                if (sb.Length > 1)
                {
                    sb.Remove(sb.Length - 1, 1);
                }
            }
            return sb.ToString();
        }
        public static bool IsBaseType(Type t)
        {
            return t.IsValueType || t == typeof(string);
        }
        private static bool JudgeDefault(Type type, object v)
        {
            bool isDefault = false;

            if (type.IsValueType)
            {
                if (type.Name == "Nullable`1")//type.GetGenericTypeDefinition() == typeof(Nullable<>)
                {
                    if (v == null)
                    {
                        isDefault = true;
                    }
                }
                else if (type.Name == "DateTime")
                {
                    if (DateTime.MinValue.Equals(v) || defaultDate.Equals(v))
                    {
                        isDefault = true;
                    }
                }
                else
                {
                    var obj = Activator.CreateInstance(type);
                    if (obj.Equals(v))
                    {
                        isDefault = true;
                    }
                }
            }
            else
            {
                if (v == null || string.IsNullOrEmpty(v.ToString()))
                {
                    isDefault = true;
                }
            }
            return isDefault;
        }
    }
}
